//ES5的继承 实质上先 创造子类的实例对象this 然后再将父类的方法添加到this上面(parent.apply(this))
//ES6的继承机制完全不一样  实质上先将父类的实例对象的属性和方法 加到this上面 (所以必须先调用super方法)，然后再用子类的构造函数修改this

class Point { /* ... */ }

class ColorPoint1 extends Point {
  constructor() {
  }
}

//let cp = new ColorPoint(); // ReferenceError

//如果子类没有定义construstor 方法 这个方法会被默认添加
class ColorPoint2 extends Point {
}

// 等同于
class ColorPoint3 extends Point {
  constructor(...args) {
    super(...args);
  }
}

//在子类的构造函数中 只有调用super之后 才可以使用this关键字
class onlySuper{
    constructor(x,y){
        this.x=x;
        this.y=y;
    }
    
    static hello(){
        console.log('你好！')
    }
}
class child extends onlySuper {
    constructor(x,y,color){
        //this.color=color;//错误
        super(x,y);
        this.color=color;//正确
    }
    say(){
       super.hello()
    }

}//上面的代码 子类的constrictor 方法没有调用super之前 就使用this关键字 结果报错 而放在super之后就正确

let cp = new child(25,8,'blue');
console.log(cp.color)
child.hello()//父类的静态方法也会被子类所继承 
console.log(cp instanceof child,cp instanceof onlySuper);//true true

//super 关键字 既可以当做函数使用 也可以当做对象使用 两种情况下 用法完全不同

//super当做函数调用 代表的是父类的构造函数constructor 子类的构造函数必须执行一次super函数  super 虽然代表了父类的构造函数 但是返回的是子类的实例 super内部的this指的是子类
console.log('*******************super作为函数*****************')
class a{
    constructor(){
        console.log(new.target.name)
    }
}

class b extends a{
    constructor(){
        super();  //相当于a.prototype.constructor.call(this)
    }
}
new a(); //a
new b(); //b
//上面代码中 super执行的时候指向的是正在执行的函数中 super()只能用在子类的构造函数(constructor)中

//super 作为对象
console.log('**************super作为对象************')
class A{
    constructor(){
        this.x = 1;
    }
    print(){
        console.log(this.x);
    }
    p(){
        return 2;
    }
     static ps(){
        console.log('ps')
    }
    ps(){
        console.log('ps2')
    }
}

class B extends A{
    constructor(x){
        super();
        console.log(super.p());
        this.x = 2;
        super.x =x;
        console.log(super.x);//udefind 这里的super.x指向的是A.prototpye.x 所以返回undefined
        console.log(this.x);//4  只想的子类B的实例 
    }
    m(){
        super.print();
    }
   static n(){
        super.ps()
    }
    n(){
        super.ps()
    }
}
let bich = new B();//2   console.log(super.p());

let bich2 = new B(4);  //2    console.log(super.p());
bich2.n()//ps2
B.n() //ps
bich2.m()//4    super.print(); 
//这里的this指的是子类B中的this  super.print() 虽然调用的是A.prototype.print()但是 其内部的this智的子类B的实例 实际上执行的super.print.call(this) 由于this指向的是是子类实例 所以通过super对属性赋值 这时候super就是this


//静态方法的使用 父类的静态方法 需要 在子类也是对应的静态方法 
console.log('*******super在静态方法中的使用********')

class Parent {
    static myMethods(msg){
        console.log('static',msg)
    }

    myMethods(msg){
        console.log('instance',msg)
    }
}

class Achild extends Parent{
    constructor(){
        super();
        console.log(super.valueOf() instanceof Achild);// Achild {} instanceof Achild 是正确的
    }
    static myMethods(msg){
        super.myMethods(msg)
    }

    myMethods(msg){
        super.myMethods(msg)
    }
}
Achild.myMethods(1);// static 1 super在静态方法中指向父类  

let achild = new Achild();
achild.myMethods(2);//instance 2 super在普通方法之中指向父类的原型对象。

//由于对象总是继承其他对象的 所以可以在任意一个对象中 使用super关键字


//类的 prototype 属性和__proto__属性  
//class 作为构造函数的语法糖 同时有prototype属性和_proto_属性。一次同时存在两条继承链条
class A1 {
}

class B1 extends A1 {
}

B1.__proto__ === A1 // true    子类的__proto__属性，表示构造函数的继承，总是指向父类。
B1.prototype.__proto__ === A1.prototype // true   类prototype属性的__proto__属性，表示方法的继承，总是指向父类的prototype属性。

let pro1 = new A1();
let pro2 = new B1();
console.log(pro2.__proto__ === pro1.__proto__) //false
console.log(pro2.__proto__.__proto__ === pro1.__proto__) //true
//因此可以通过修改子类实例的.__proto__.__proto__ 属性 可以修改父类实例的行为


